<!DOCTYPE html>
<html lang="zh-cn">
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="referrer" content="origin" />
    <title>python中的轻量级定时任务调度库：schedule - _小苹果 - 博客园</title>
<meta property="og:description" content="提到定时任务调度的时候，相信很多人会想到芹菜celery，要么就写个脚本塞到crontab中。不过，一个小的定时脚本，要用celery的话太“重”了。所以，我找到了一个轻量级的定时任务调度的库：sch" />
    <link type="text/css" rel="stylesheet" href="/bundles/blog-common.css?v=-duj5vpGTntb85GJoM3iRI972XwWcI-j8zmqDzyfu2w1"/>
<link id="MainCss" type="text/css" rel="stylesheet" href="/skins/facebook/bundle-facebook.css?v=qIugXTv-81WNv9VUYnmd-OAOMQjLdGzefMwj-nSLyvo1"/>
<link id="mobile-style" media="only screen and (max-width: 767px)" type="text/css" rel="stylesheet" href="/skins/facebook/bundle-facebook-mobile.css?v=n7iuSqbfjmydeTtXmZpjV4aS2Tk9Y0f_i7pXCLcajAs1"/>
    <link title="RSS" type="application/rss+xml" rel="alternate" href="https://www.cnblogs.com/anpengapple/rss"/>
    <link title="RSD" type="application/rsd+xml" rel="EditURI" href="https://www.cnblogs.com/anpengapple/rsd.xml"/>
<link type="application/wlwmanifest+xml" rel="wlwmanifest" href="https://www.cnblogs.com/anpengapple/wlwmanifest.xml"/>
    <script src="//common.cnblogs.com/scripts/jquery-2.2.0.min.js"></script>
    <script>var currentBlogId=130491;var currentBlogApp='anpengapple',cb_enable_mathjax=false;var isLogined=false;</script>
    <script src="/bundles/blog-common.js?v=e0U209y0KhDmz427-vMnFPWz2_XPP7u3X-dzpeE662I1" type="text/javascript"></script>
</head>
<body>
<a name="top"></a>


<div id="home">
<div id="header">
	<div id="blogTitle">
		
<!--done-->
<h1><a id="Header2_HeaderTitle" class="headermaintitle" href="https://www.cnblogs.com/anpengapple/">小苹果的苹果树</a></h1>
<h2>记录技术点滴</h2>



		
	</div><!--end: blogTitle 博客的标题和副标题 -->
	<div id="navigator">
		
<!--done-->
			<ul id="navList">
				<li><a id="blog_nav_sitehome" class="menu" href="https://www.cnblogs.com/">博客园</a></li>
				<li><a id="blog_nav_myhome" class="menu" href="https://www.cnblogs.com/anpengapple/">首页</a></li>
				<li><a id="blog_nav_newpost" class="menu" rel="nofollow" href="https://i.cnblogs.com/EditPosts.aspx?opt=1">新随笔</a></li>
				<li><a id="blog_nav_contact" accesskey="9" class="menu" rel="nofollow" href="https://msg.cnblogs.com/send/_%E5%B0%8F%E8%8B%B9%E6%9E%9C">联系</a></li>
				<li><a id="blog_nav_admin" class="menu" rel="nofollow" href="https://i.cnblogs.com/">管理</a></li>
				<li><a id="blog_nav_rss" class="menu" href="https://www.cnblogs.com/anpengapple/rss">订阅</a>
				<a id="blog_nav_rss_image" class="aHeaderXML" href="https://www.cnblogs.com/anpengapple/rss"><img src="//www.cnblogs.com/images/xml.gif" alt="订阅" /></a></li>
			</ul>


		<div class="blogStats">
			
			<div id="blog_stats">
<!--done-->
随笔- 61&nbsp;
文章- 0&nbsp;
评论- 41&nbsp;
</div>
			
		</div><!--end: blogStats -->
	</div><!--end: navigator 博客导航栏 -->
</div><!--end: header 头部 -->

<div id="main">
	<div id="mainContent">
	<div class="forFlow">
		
        <div id="post_detail">
<!--done-->
<div id="topics">
	<div class = "post">
		<h1 class = "postTitle">
			<a id="cb_post_title_url" class="postTitle2" href="https://www.cnblogs.com/anpengapple/p/8051923.html">python中的轻量级定时任务调度库：schedule</a>
		</h1>
		<div class="clear"></div>
		<div class="postBody">
			<div id="cnblogs_post_body" class="blogpost-body"><div>提到定时任务调度的时候，相信很多人会想到<span style="text-decoration: line-through;">芹菜</span>celery，要么就写个脚本塞到crontab中。不过，一个小的定时脚本，要用celery的话太&ldquo;重&rdquo;了。所以，我找到了一个轻量级的定时任务调度的库：schedule。</div>
<div>&nbsp;</div>
<div>库的安装还是最简单的pip install schedule，使用起来也是很容易理解的。我们从最简单的栗子看起：</div>
<div>&nbsp;</div>
<div>
<div class="cnblogs_code">
<pre><span style="color: #0000ff;">import</span><span style="color: #000000;"> schedule
</span><span style="color: #0000ff;">import</span><span style="color: #000000;"> time
 
</span><span style="color: #0000ff;">def</span><span style="color: #000000;"> job():
    </span><span style="color: #0000ff;">print</span>(<span style="color: #800000;">"</span><span style="color: #800000;">I'm working...</span><span style="color: #800000;">"</span><span style="color: #000000;">)
 
schedule.every(</span>10<span style="color: #000000;">).minutes.do(job)
schedule.every().hour.do(job)
schedule.every().day.at(</span><span style="color: #800000;">"</span><span style="color: #800000;">10:30</span><span style="color: #800000;">"</span><span style="color: #000000;">).do(job)
schedule.every(</span>5).to(10<span style="color: #000000;">).days.do(job)
schedule.every().monday.do(job)
schedule.every().wednesday.at(</span><span style="color: #800000;">"</span><span style="color: #800000;">13:15</span><span style="color: #800000;">"</span><span style="color: #000000;">).do(job)
 
</span><span style="color: #0000ff;">while</span><span style="color: #000000;"> True:
    schedule.run_pending()
    time.sleep(</span>1)</pre>
</div>
<p>&nbsp;</p>
</div>
<div>这是在pypi上面给出的示例。这个栗子简单到我不需要怎么解释。而且，通过这个栗子，我们也可以知道，schedule其实就只是个定时器。在while True死循环中，schedule.run_pending()是保持schedule一直运行，去查询上面那一堆的任务，在任务中，就可以设置不同的时间去运行。跟crontab是类似的。</div>
<div>&nbsp;</div>
<div>但是，如果是多个任务运行的话，实际上它们是按照顺序从上往下挨个执行的。如果上面的任务比较复杂，会影响到下面任务的运行时间。比如我们这样：</div>
<div>&nbsp;</div>
<div>
<div class="cnblogs_code">
<pre><span style="color: #0000ff;">import</span><span style="color: #000000;"> datetime
</span><span style="color: #0000ff;">import</span><span style="color: #000000;"> schedule
</span><span style="color: #0000ff;">import</span><span style="color: #000000;"> time
 
</span><span style="color: #0000ff;">def</span><span style="color: #000000;"> job1():
    </span><span style="color: #0000ff;">print</span>(<span style="color: #800000;">"</span><span style="color: #800000;">I'm working for job1</span><span style="color: #800000;">"</span><span style="color: #000000;">)
    time.sleep(</span>2<span style="color: #000000;">)
    </span><span style="color: #0000ff;">print</span>(<span style="color: #800000;">"</span><span style="color: #800000;">job1:</span><span style="color: #800000;">"</span><span style="color: #000000;">, datetime.datetime.now())
 
</span><span style="color: #0000ff;">def</span><span style="color: #000000;"> job2():
    </span><span style="color: #0000ff;">print</span>(<span style="color: #800000;">"</span><span style="color: #800000;">I'm working for job2</span><span style="color: #800000;">"</span><span style="color: #000000;">)
    time.sleep(</span>2<span style="color: #000000;">)
    </span><span style="color: #0000ff;">print</span>(<span style="color: #800000;">"</span><span style="color: #800000;">job2:</span><span style="color: #800000;">"</span><span style="color: #000000;">, datetime.datetime.now())
 
</span><span style="color: #0000ff;">def</span><span style="color: #000000;"> run():
    schedule.every(</span>10<span style="color: #000000;">).seconds.do(job1)
    schedule.every(</span>10<span style="color: #000000;">).seconds.do(job2)
 
    </span><span style="color: #0000ff;">while</span><span style="color: #000000;"> True:
        schedule.run_pending()
        time.sleep(</span>1)</pre>
</div>
<p>&nbsp;</p>
</div>
<div>接下来你就会发现，两个定时任务并不是10秒运行一次，而是12秒。是的。由于job1和job2本身的执行时间，导致任务延迟了。</div>
<div>&nbsp;</div>
<div>其实解决方法也很简单：用多线程/多进程。不要幼稚地问我&ldquo;python中的多线程不是没有用吗？&rdquo;这是两码事。开了一条线程，就把job独立出去运行了，不会占主进程的cpu时间，schedule并没有花掉执行一个任务的时间，它的开销只是开启一条线程的时间，所以，下一次执行就变成了10秒后而不是12秒后。</div>
<div>&nbsp;</div>
<div>
<div class="cnblogs_code">
<pre><span style="color: #0000ff;">import</span><span style="color: #000000;"> datetime
</span><span style="color: #0000ff;">import</span><span style="color: #000000;"> schedule
</span><span style="color: #0000ff;">import</span><span style="color: #000000;"> threading
</span><span style="color: #0000ff;">import</span><span style="color: #000000;"> time
 
</span><span style="color: #0000ff;">def</span><span style="color: #000000;"> job1():
    </span><span style="color: #0000ff;">print</span>(<span style="color: #800000;">"</span><span style="color: #800000;">I'm working for job1</span><span style="color: #800000;">"</span><span style="color: #000000;">)
    time.sleep(</span>2<span style="color: #000000;">)
    </span><span style="color: #0000ff;">print</span>(<span style="color: #800000;">"</span><span style="color: #800000;">job1:</span><span style="color: #800000;">"</span><span style="color: #000000;">, datetime.datetime.now())
 
</span><span style="color: #0000ff;">def</span><span style="color: #000000;"> job2():
    </span><span style="color: #0000ff;">print</span>(<span style="color: #800000;">"</span><span style="color: #800000;">I'm working for job2</span><span style="color: #800000;">"</span><span style="color: #000000;">)
    time.sleep(</span>2<span style="color: #000000;">)
    </span><span style="color: #0000ff;">print</span>(<span style="color: #800000;">"</span><span style="color: #800000;">job2:</span><span style="color: #800000;">"</span><span style="color: #000000;">, datetime.datetime.now())
 
</span><span style="color: #0000ff;">def</span><span style="color: #000000;"> job1_task():
    threading.Thread(target</span>=<span style="color: #000000;">job1).start()
 
</span><span style="color: #0000ff;">def</span><span style="color: #000000;"> job2_task():
    threading.Thread(target</span>=<span style="color: #000000;">job2).start()
 
</span><span style="color: #0000ff;">def</span><span style="color: #000000;"> run():
    schedule.every(</span>10<span style="color: #000000;">).seconds.do(job1_task)
    schedule.every(</span>10<span style="color: #000000;">).seconds.do(job2_task)
 
    </span><span style="color: #0000ff;">while</span><span style="color: #000000;"> True:
        schedule.run_pending()
        time.sleep(</span>1)</pre>
</div>
<p>&nbsp;</p>
</div>
<div>就是这么简单。</div>
<div>&nbsp;</div>
<div>唯一要注意的是，这里面job不应当是死循环类型的，也就是说，这个线程应该有一个执行完毕的出口。一是因为线程万一僵死，会是非常棘手的问题；二是下一次定时任务还会开启一个新的线程，执行次数多了就会演变成灾难。如果schedule的时间间隔设置得比job执行的时间短，一样会线程堆积形成灾难，所以，还是需要注意一下的。</div>
<div>&nbsp;</div>
<div>schedule这个库使用起来比较简单，内容不是很多。我这里介绍的大概用法基本上够用了，还想了解其他特性的话，可以参考官网：<a href="https://schedule.readthedocs.io/en/stable/">https://schedule.readthedocs.io/en/stable/</a></div>
<div>&nbsp;</div>
<div>就酱。</div></div><div id="MySignature"></div>
<div class="clear"></div>
<div id="blog_post_info_block">
<div id="BlogPostCategory"></div>
<div id="EntryTag"></div>
<div id="blog_post_info">
</div>
<div class="clear"></div>
<div id="post_next_prev"></div>
</div>


		</div>
		<div class = "postDesc">posted @ <span id="post-date">2017-12-17 13:43</span> <a href='https://www.cnblogs.com/anpengapple/'>_小苹果</a> 阅读(<span id="post_view_count">...</span>) 评论(<span id="post_comment_count">...</span>)  <a href ="https://i.cnblogs.com/EditPosts.aspx?postid=8051923" rel="nofollow">编辑</a> <a href="#" onclick="AddToWz(8051923);return false;">收藏</a></div>
	</div>
	<script type="text/javascript">var allowComments=true,cb_blogId=130491,cb_entryId=8051923,cb_blogApp=currentBlogApp,cb_blogUserGuid='87a426f9-cfe9-e111-aa3f-842b2b196315',cb_entryCreatedDate='2017/12/17 13:43:00';loadViewCount(cb_entryId);var cb_postType=1;var isMarkdown=false;</script>
	
</div>
<!--end: topics 文章、评论容器-->
</div><a name="!comments"></a><div id="blog-comments-placeholder"></div><script type="text/javascript">var commentManager = new blogCommentManager();commentManager.renderComments(0);</script>
<div id='comment_form' class='commentform'>
<a name='commentform'></a>
<div id='divCommentShow'></div>
<div id='comment_nav'><span id='span_refresh_tips'></span><a href='javascript:void(0);' onclick='return RefreshCommentList();' id='lnk_RefreshComments' runat='server' clientidmode='Static'>刷新评论</a><a href='#' onclick='return RefreshPage();'>刷新页面</a><a href='#top'>返回顶部</a></div>
<div id='comment_form_container'></div>
<div class='ad_text_commentbox' id='ad_text_under_commentbox'></div>
<div id='ad_t2'></div>
<div id='opt_under_post'></div>
<script async='async' src='https://www.googletagservices.com/tag/js/gpt.js'></script>
<script>
  var googletag = googletag || {};
  googletag.cmd = googletag.cmd || [];
</script>
<script>
  googletag.cmd.push(function() {
        googletag.defineSlot('/1090369/C1', [300, 250], 'div-gpt-ad-1546353474406-0').addService(googletag.pubads());
        googletag.defineSlot('/1090369/C2', [468, 60], 'div-gpt-ad-1539008685004-0').addService(googletag.pubads());
        googletag.pubads().enableSingleRequest();
        googletag.enableServices();
  });
</script>
<div id='cnblogs_c1' class='c_ad_block'>
<div id='div-gpt-ad-1546353474406-0' style='height:250px; width:300px;'>
<script>
if(canShowAdsense()) {
    googletag.cmd.push(function() { googletag.display('div-gpt-ad-1546353474406-0'); });
}
</script>
</div>
</div>
<div id='under_post_news'></div>
<div id='cnblogs_c2' class='c_ad_block'>
    <div id='div-gpt-ad-1539008685004-0' style='height:60px; width:468px;'>
    <script>
    if(canShowAdsense()) {
        googletag.cmd.push(function() { googletag.display('div-gpt-ad-1539008685004-0'); });
    }
    </script>
    </div>
</div>
<div id='under_post_kb'></div>
<div id='HistoryToday' class='c_ad_block'></div>
<script type='text/javascript'>
 if(enablePostBottom()) {
    codeHighlight();
    fixPostBody();
    setTimeout(function () { incrementViewCount(cb_entryId); }, 50);
    deliverAdT2();
    deliverAdC1();
    deliverAdC2();    
    loadNewsAndKb();
    loadBlogSignature();
    LoadPostInfoBlock(cb_blogId, cb_entryId, cb_blogApp, cb_blogUserGuid);
    GetPrevNextPost(cb_entryId, cb_blogId, cb_entryCreatedDate, cb_postType);
    loadOptUnderPost();
    GetHistoryToday(cb_blogId, cb_blogApp, cb_entryCreatedDate);  
}
</script>
</div>

    
	</div><!--end: forFlow -->
	</div><!--end: mainContent 主体内容容器-->

	<div id="sideBar">
		<div id="sideBarMain">
		<div id="calendar"><div id="blog-calendar" style="display:none"></div><script type="text/javascript">loadBlogDefaultCalendar();</script></div>
			
<!--done-->
<div class="newsItem">
<h3 class="catListTitle">公告</h3>
	<div id="blog-news"></div><script type="text/javascript">loadBlogNews();</script>
</div>
			
			
			<DIV id="leftcontentcontainer">
				<div id="blog-sidecolumn"></div><script type="text/javascript">loadBlogSideColumn();</script>
			</DIV>
			
		</div><!--end: sideBarMain -->
	</div><!--end: sideBar 侧边栏容器 -->
	<div class="clear"></div>
	</div><!--end: main -->
	<div class="clear"></div>
	<div id="footer">
		
<!--done-->
Copyright &copy;2019 _小苹果
	</div><!--end: footer -->
</div><!--end: home 自定义的最大容器 -->

</body>
</html>
